// SDArray.h: interface for the TSDArray class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_TSDArray_H__275B5F31_D3A6_4670_ADD9_E1F828AFCF5A__INCLUDED_)
#define AFX_TSDArray_H__275B5F31_D3A6_4670_ADD9_E1F828AFCF5A__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/** \file SDArray.h
 *
 * template class for Array
 */

#include <assert.h>
#include <stdlib.h>

#define		_SD_INIT_SIZE		5
#define		_SD_INIT_STEP		1

/// template class, like _SDByteBuffer
template <class TYPE>
class TSDArray
{
public:
	TSDArray();
	~TSDArray();

public:
	/// to initialize
	void InitStepSize(int AnInitSize=_SD_INIT_SIZE, int AnStep=_SD_INIT_STEP);
	/// to append a new item
	int Add(TYPE Item);
	/// to get direct write access at given index
	TYPE& operator[](int nIndex);
	/// to get direct read access at given index
	const TYPE& operator[](int nIndex) const;
	/// to get direct write access of all data
	TYPE* GetData(void);
	/// to get direct read access of all data
	const TYPE* GetData(void) const;
	/// to get current data count
	int GetSize() const;
	/// to get current allocated size
	int GetAllocSize() const;
	/// to remove all data(may/maynot free buffer)
	void RemoveAll(BOOL AbFreeExtra = FALSE);
	/// to insert an item
	BOOL InsertAt(int nIndex, TYPE item);
	/// to remove an item
	BOOL RemoveAt(int nIndex, int nCount = 1);
	/// to set new size
	BOOL SetSize(int nSize);
	/// to get element data
	TYPE& GetAt(int nIndex);
	/// to set element data
	void SetAt(int nIndex, TYPE Item);
	/// to append another array
	TSDArray& Append(const TSDArray& list);

protected:
	void Clear();
	void Destroy();
	BOOL GrowSize(int nRequestSize);

protected:
	int	m_iStep;	///< step size of buffer
	int	m_iInitSize;///< initial size of buffer
	int	m_nCount;	///< count of using buffer
	int	m_nAlloc;	///< allocated size of buffer
	TYPE*	m_pData;	///< buffer head pointer
};

template <class TYPE>
TSDArray<TYPE>::TSDArray(void)
{
	Clear();
	m_iInitSize = _SD_INIT_SIZE;
	m_iStep = _SD_INIT_STEP;
}

template <class TYPE>
TSDArray<TYPE>::~TSDArray()
{
	Destroy();
}

template <class TYPE>
void TSDArray<TYPE>::InitStepSize(int AnInitSize, int AnStep)
{
	m_iInitSize = (AnInitSize>0 ? AnInitSize : _SD_INIT_SIZE);
	m_iStep = (AnStep>0 ? AnStep : _SD_INIT_STEP);
}

template <class TYPE>
int	TSDArray<TYPE>::Add(TYPE Item)
{
	if (m_nCount>=m_nAlloc && !GrowSize(0))
		return -1;
	m_pData[m_nCount++] = Item;
	return m_nCount - 1;
}

template <class TYPE>
inline TYPE& TSDArray<TYPE>::operator[](int nIndex)
{
	assert(0<=nIndex && nIndex<m_nCount);
	return m_pData[nIndex];
}

template <class TYPE>
inline const TYPE& TSDArray<TYPE>::operator[](int nIndex) const
{
	assert(0<=nIndex && nIndex<m_nCount);
	return m_pData[nIndex];
}

template <class TYPE>
inline TYPE* TSDArray<TYPE>::GetData(void)
{
	assert(this != NULL);
	return m_pData;
}

template <class TYPE>
inline const TYPE* TSDArray<TYPE>::GetData(void) const
{
	assert(this != NULL);
	return m_pData;
}

template <class TYPE>
inline int	TSDArray<TYPE>::GetSize() const
{
	assert(this != NULL);
	return m_nCount;
}

template <class TYPE>
inline int	TSDArray<TYPE>::GetAllocSize() const
{
	assert(this != NULL);
	return m_nAlloc;
}

template <class TYPE>
void TSDArray<TYPE>::RemoveAll(BOOL AbFreeExtra)
{
	assert(this != NULL);
	if (m_pData != NULL)
	{
		if (AbFreeExtra)
			Destroy();
		else
			m_nCount = 0;
	}
}

template <class TYPE>
BOOL TSDArray<TYPE>::InsertAt(int nIndex, TYPE item)
{
	assert(this != NULL);
	if (nIndex<0 || nIndex>m_nCount)
		return FALSE;
	GrowSize(0);
	for(int i=m_nCount-1; i>=nIndex; i--)
		m_pData[i+1] = m_pData[i];
	m_pData[nIndex] = item;
	m_nCount++;
	return TRUE;
}

template <class TYPE>
BOOL TSDArray<TYPE>::RemoveAt(int nIndex, int nCount)
{
	assert(this != NULL);
	if (nIndex<0 || nCount<=0 || nIndex+nCount>m_nCount)
		return FALSE;
	int nMaxIndex = m_nCount - nCount;
	for(int i=nIndex; i<nMaxIndex; i++)
		m_pData[i] = m_pData[i + nCount];
	m_nCount -= nCount;
	return TRUE;
}

template <class TYPE>
BOOL TSDArray<TYPE>::SetSize(int nSize)
{
	assert(this != NULL);
	if (nSize <= 0)
	{
		Destroy();
		return TRUE;
	}
	if (m_nAlloc < nSize)
	{
		TYPE *p = (TYPE *)realloc(m_pData, nSize*sizeof(TYPE));
		if (p == NULL)
			return FALSE;
		memset(p+m_nAlloc, 0, sizeof(TYPE)*(nSize-m_nAlloc));
		m_pData = p;
		m_nAlloc = nSize;
	}
	m_nCount = nSize;
	return TRUE;
}

template <class TYPE>
TYPE& TSDArray<TYPE>::GetAt(int nIndex)
{
	assert(this != NULL);
	assert(0<=nIndex && nIndex<m_nCount);
	return m_pData[nIndex];
}

template <class TYPE>
void TSDArray<TYPE>::SetAt(int nIndex, TYPE Item)
{
	assert(this != NULL);
	assert(0<=nIndex && nIndex<m_nCount);
	m_pData[nIndex] = Item;
}

template <class TYPE>
void TSDArray<TYPE>::Clear()
{
	m_nAlloc = 0;
	m_nCount = 0;
	m_pData = NULL;
}

template <class TYPE>
void TSDArray<TYPE>::Destroy()
{
	if ( m_pData!=NULL ) 
	{
		free(m_pData);
		Clear();
	}
}

template <class TYPE>
BOOL TSDArray<TYPE>::GrowSize(int nRequestSize)
{
	int nSize = (m_nCount>0 ? (m_nCount+m_iStep) : m_iInitSize);
	if (nRequestSize > 0)
		nSize = max(m_nCount+nRequestSize, nSize);
	TYPE *p = (TYPE *)realloc(m_pData, nSize*sizeof(TYPE));
	if (p == NULL)
		return FALSE;
	m_pData = p;
	m_nAlloc = nSize;
	return TRUE;
}

template <class TYPE>
TSDArray<TYPE>& TSDArray<TYPE>::Append(const TSDArray<TYPE>& list)
{
	int nAdd = list.m_nCount;
	if (m_nCount + nAdd > m_nAlloc)
		GrowSize(nAdd);
	for(int i=0; i<nAdd; i++)
		m_pData[m_nCount+i] = list.m_pData[i];
	m_nCount += nAdd;
	return *this;
}
#endif // !defined(AFX_TSDArray_H__275B5F31_D3A6_4670_ADD9_E1F828AFCF5A__INCLUDED_)
